﻿using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using Java.Util;
using SnakeRemote.Models;
using SnakeRemote.Services.BluetoothService;
using System.Collections.Immutable;
using System.Linq;

namespace SnakeRemote.ViewModels
{
    public sealed partial class MainViewModel : ObservableObject, IDisposable
    {
        private readonly IBluetoothService bluetooth;
        public MainViewModel(IBluetoothService bluetooth)
        {
            this.bluetooth = bluetooth;

            RefreshBluetoothState();
            Prompt = "你好";
        }

        [RelayCommand]
        void RefreshBluetoothState()
        {
            Prompt = "正在刷新……";

            if (!bluetooth.IsEnabled)
            {
                Prompt = "蓝牙功能未开启";
                BondedSnakes = null;
                return;
            }

            var selected = SelectedSnake?.Address;
            BondedSnakes = bluetooth.GetBondedDevices().ToImmutableList();
            if (BondedSnakes.Count > 0)
            {
                SelectedSnake = BondedSnakes.FirstOrDefault(
                    snake => snake.Address == selected, BondedSnakes[0]);
            }

            Prompt = "刷新成功";
        }

        [ObservableProperty]
        IReadOnlyList<IBluetoothDeviceInfo> bondedSnakes = null;

        [ObservableProperty]
        IBluetoothDeviceInfo selectedSnake = null;

        private static readonly UUID sspUuid = UUID.FromString("00001101-0000-1000-8000-00805f9b34fb");

        [ObservableProperty]
        bool isConnecting = false;

        [RelayCommand]
        async Task ConnectSnakeAsync()
        {
            if (IsConnecting)
                return;
            IsConnecting = true;

            DisconnectSnake();
            Prompt = "正在连接……";
            try
            {
                var connection = bluetooth.CreateConnection(selectedSnake?.Address, sspUuid);
                await connection.ConnectAsync();
                Connection = connection;
                Prompt = "连接成功";
                await StopMovingAsync();
            }
            catch (Exception ex)
            {
                Prompt = $"连接失败：{ex.Message}";
            }
            finally
            {
                IsConnecting = false;
            }
        }

        [ObservableProperty]
        BluetoothConnection connection = null;

        [RelayCommand]
        void DisconnectSnake()
        {
            if(Connection is not null)
            {
                Prompt = "正在断开连接……";
                Connection.Dispose();
                Connection = null;
                Prompt = "已断开连接";
            }
        }

        [ObservableProperty]
        string prompt = null;

        [ObservableProperty]
        SnakeMovingState movingState = SnakeMovingState.StayStill;
        private async Task ChangeMovingStateAsync(SnakeMovingState state)
        {
            if (Connection is null)
                return;
            Prompt = "正在发送指令……";
            try
            {
                await Connection.OutputStream.WriteAsync(new byte[] { (byte)state });
                MovingState = state;
                Prompt = "指令已发送";
            }
            catch (Exception ex)
            {
                Prompt = $"发送指令时遇到错误：{ex.Message}";
            }
        }
        [RelayCommand]
        async Task MoveForwardAsync()
        {
            await ChangeMovingStateAsync(SnakeMovingState.MoveForward);
        }
        [RelayCommand]
        async Task MoveBackwardAsync()
        {
            await ChangeMovingStateAsync(SnakeMovingState.MoveBackward);
        }
        [RelayCommand]
        async Task MoveLeftwardAsync()
        {
            await ChangeMovingStateAsync(SnakeMovingState.MoveLeftward);
        }
        [RelayCommand]
        async Task MoveRightwardAsync()
        {
            await ChangeMovingStateAsync(SnakeMovingState.MoveRightward);
        }
        [RelayCommand]
        async Task StopMovingAsync()
        {
            await ChangeMovingStateAsync(SnakeMovingState.StayStill);
        }

        public void Dispose()
        {
            connection?.Dispose();
        }
    }
}
